package com.example.picturebacked.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.picturebacked.annotation.AuthCheck;
import com.example.picturebacked.api.aliyunai.AliYunAiApi;
import com.example.picturebacked.api.aliyunai.model.CreateOutPaintingTaskResponse;
import com.example.picturebacked.api.aliyunai.model.GetOutPaintingTaskResponse;
import com.example.picturebacked.api.imagesearch.ImageSearchApiFacade;
import com.example.picturebacked.api.imagesearch.model.ImageSearchResult;
import com.example.picturebacked.common.BaseResponse;
import com.example.picturebacked.common.DeleteRequest;
import com.example.picturebacked.common.ResultUtils;
import com.example.picturebacked.contant.UserContant;
import com.example.picturebacked.exception.BusinessException;
import com.example.picturebacked.exception.ErrorCode;
import com.example.picturebacked.exception.ThrowUtils;
import com.example.picturebacked.manager.CosManager;
import com.example.picturebacked.manager.auth.SpaceUserAuthManager;
import com.example.picturebacked.manager.auth.StpKit;
import com.example.picturebacked.manager.auth.annotation.SaSpaceCheckPermission;
import com.example.picturebacked.manager.auth.model.SpaceUserPermissionConstant;
import com.example.picturebacked.model.dto.file.UploadPictureResult;
import com.example.picturebacked.model.dto.picture.*;
import com.example.picturebacked.model.entity.Picture;
import com.example.picturebacked.model.entity.Space;
import com.example.picturebacked.model.entity.User;
import com.example.picturebacked.model.enums.PictureReviewStatusEnum;
import com.example.picturebacked.model.vo.PictureTagCategory;
import com.example.picturebacked.model.vo.PictureVO;
import com.example.picturebacked.service.PictureService;
import com.example.picturebacked.service.SpaceService;
import com.example.picturebacked.service.UserService;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.qcloud.cos.model.COSObject;
import com.qcloud.cos.model.COSObjectInputStream;
import com.qcloud.cos.utils.IOUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import shade.kotlin.jvm.Throws;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
@RequestMapping("/picture")
@Api(tags = "图片接口")
public class PictureController {

    @Resource
    private PictureService pictureService;

    @Resource
    private UserService userService;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private SpaceService spaceService;
    @Resource
    private SpaceUserAuthManager spaceUserAuthManager;

    @Resource
    private AliYunAiApi aliYunAiApi;

    private final Cache<String, String> LOCAL_CACHE =
            Caffeine.newBuilder().initialCapacity(1024)
                    .maximumSize(10000L)
                    // 缓存 5 分钟移除
                    .expireAfterWrite(5L, TimeUnit.MINUTES)
                    .build();


    /**
     * 图片上传
     */
    @PostMapping("/upload")
    @ApiOperation("本地图片上传")
    @SaSpaceCheckPermission(value = SpaceUserPermissionConstant.PICTURE_UPLOAD)
    public BaseResponse<PictureVO> uploadPicture(@RequestPart("file") MultipartFile multipartFile,
                                                 PictureUploadRequest pictureUploadRequest,
                                                 HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        PictureVO pictureVO = pictureService.uploadPicture(multipartFile, pictureUploadRequest, loginUser);
        return ResultUtils.success(pictureVO);
    }

    /**
     * 通过URL进行文件上传
     */
    @PostMapping("/upload/url")
    @ApiOperation("URL图片上传")
    @SaSpaceCheckPermission(value = SpaceUserPermissionConstant.PICTURE_UPLOAD)
    public BaseResponse<PictureVO> uploadPictureByUrl(@RequestBody PictureUploadRequest pictureUploadRequest,
                                                      HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        String fielUrl = pictureUploadRequest.getFileUrl();
        PictureVO pictureVO = pictureService.uploadPicture(fielUrl, pictureUploadRequest, loginUser);
        return ResultUtils.success(pictureVO);
    }

    /**
     * 删除图片
     */
    @PostMapping("/delete")
    @SaSpaceCheckPermission(value = SpaceUserPermissionConstant.PICTURE_DELETE)
    public BaseResponse<Boolean> deletePicture(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
        if (deleteRequest == null || deleteRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        User loginUser = userService.getLoginUser(request);
        pictureService.deletePicture(deleteRequest.getId(), loginUser);
        return ResultUtils.success(true);
    }

    /**
     * 更新图片
     * 仅管理员可用
     */
    @PostMapping("/update")
    @ApiOperation("更新图片")
    @AuthCheck(mustRole = UserContant.ADMIN_ROLE)
    public BaseResponse<Boolean> updatePicture(@RequestBody PictureUpdateRequest pictureUpdateRequest, HttpServletRequest request) {
        if (pictureUpdateRequest == null || pictureUpdateRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Picture picture = new Picture();
        BeanUtil.copyProperties(pictureUpdateRequest, picture);
        // 将List转为String
        picture.setTags(JSONUtil.toJsonStr(pictureUpdateRequest.getTags()));

        // 数据校验
        pictureService.validPicture(picture);
        Long id = pictureUpdateRequest.getId();
        Picture updatePicture = pictureService.getById(id);
        ThrowUtils.throwIf(updatePicture == null, ErrorCode.NOT_FOUND_ERROR);
        User loginUser = userService.getLoginUser(request);
        pictureService.fillReviewParams(picture, loginUser);

        boolean b = pictureService.updateById(picture);
        ThrowUtils.throwIf(!b, ErrorCode.OPERATION_ERROR);
        return ResultUtils.success(true);
    }

    /**
     * 根据id获取图片（仅管理员可用，并且信息不脱敏）
     */
    @GetMapping("/get")
    @ApiOperation("管理员根据id获取图片")
    @AuthCheck(mustRole = UserContant.ADMIN_ROLE)
    public BaseResponse<Picture> getPictureById(long id, HttpServletRequest request) {
        if (id <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Picture searchPicture = pictureService.getById(id);
        ThrowUtils.throwIf(searchPicture == null, ErrorCode.NOT_FOUND_ERROR);
        return ResultUtils.success(searchPicture);
    }

    /**
     * 根据id获取图片（封装类） 用户使用
     */
    @GetMapping("/get/vo")
    @ApiOperation("用户根据id获取图片")
    public BaseResponse<PictureVO> getPictureVOById(long id, HttpServletRequest request) {
        if (id <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Picture searchPicture = pictureService.getById(id);
        ThrowUtils.throwIf(searchPicture == null, ErrorCode.NOT_FOUND_ERROR);

        Space space = null ;
        Long spaceId = searchPicture.getSpaceId();
        if (spaceId != null) {
            boolean hasPermission = StpKit.SPACE.hasPermission(SpaceUserPermissionConstant.PICTURE_VIEW);
            ThrowUtils.throwIf(!hasPermission, ErrorCode.NO_AUTH_ERROR);
            // 如果空间id不为空则表示获取的是私人空间的图片，需要检验权限是否有该空间的权限
//            User loginUser = userService.getLoginUser(request);
//            pictureService.checkPictureAuth(searchPicture, loginUser);
            space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR,"孔空间不存在");
        }
        User loginUser = userService.getLoginUser(request);
        List<String> permissionList = spaceUserAuthManager.getPermissionList(space, loginUser);
        PictureVO pictureVO = pictureService.getPictureVO(searchPicture, request);
        pictureVO.setPermissionList(permissionList);
        ThrowUtils.throwIf(searchPicture == null, ErrorCode.NOT_FOUND_ERROR);
        return ResultUtils.success(pictureVO);
    }

    /**
     * 分页获取图片列表（仅管理员可用）
     */
    @PostMapping("/list/page")
    @ApiOperation("管理员分页获取图片列表")
    @AuthCheck(mustRole = UserContant.ADMIN_ROLE)
    public BaseResponse<Page<Picture>> listPictureByPage(@RequestBody PictureQueryRequest pictureQueryRequest,
                                                         HttpServletRequest request) {

        long current = pictureQueryRequest.getCurrent();
        long pageSize = pictureQueryRequest.getPageSize();
        // 根据当前页数以及页数据大小，通过使用getQueryWrapepr返回的查询条件进行分页查询
        Page<Picture> picturePage = pictureService.page(new Page<>(current, pageSize),
                pictureService.getQueryWrapepr(pictureQueryRequest));
        return ResultUtils.success(picturePage);
    }


    /**
     * 分页获取图片列表（用户使用）
     */
    @PostMapping("/list/page/vo")
    @ApiOperation("用户分页获取图片列表")
    public BaseResponse<Page<PictureVO>> listPictureVOByPage(@RequestBody PictureQueryRequest pictureQueryRequest,
                                                             HttpServletRequest request) {
        long current = pictureQueryRequest.getCurrent();
        long pageSize = pictureQueryRequest.getPageSize();
        // 限制爬虫，防止爬虫直接将所有图片都爬取
        ThrowUtils.throwIf(pageSize > 200, ErrorCode.PARAMS_ERROR);

        // 空间权限校验
        Long spaceId = pictureQueryRequest.getSpaceId();
        if (spaceId == null) {
            // 公共图库，仅能查看已过审的数据
            // 普通用户默认只能查看已过审的数据
            pictureQueryRequest.setReviewStatus(PictureReviewStatusEnum.PASS.getValue());
            pictureQueryRequest.setNullSpaceId(true);
        } else {
//            // 检验图库权限
            boolean hasPermission = StpKit.SPACE.hasPermission(SpaceUserPermissionConstant.PICTURE_VIEW);
            ThrowUtils.throwIf(!hasPermission, ErrorCode.NO_AUTH_ERROR);

//            User loginUser = userService.getLoginUser(request);
//            Space space = spaceService.getById(spaceId);
//            ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR);
//            if (!loginUser.getId().equals(space.getUserId())) {
//                throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "没有空间权限");
//            }
        }
        // 查询数据库
        Page<Picture> picturePage = pictureService.page(new Page<>(current, pageSize),
                pictureService.getQueryWrapepr(pictureQueryRequest));

        return ResultUtils.success(pictureService.getPictureVOPage(picturePage, request));
    }

    /**
     * 分页获取图片列表（用户使用）
     */
    @PostMapping("/list/page/vo/cache")
    @ApiOperation("使用缓存用户分页获取图片列表")
    public BaseResponse<Page<PictureVO>> listPictureVOByPageWithCache(@RequestBody PictureQueryRequest pictureQueryRequest,
                                                                      HttpServletRequest request) {
        long current = pictureQueryRequest.getCurrent();
        long pageSize = pictureQueryRequest.getPageSize();
        // 限制爬虫，防止爬虫直接将所有图片都爬取
        ThrowUtils.throwIf(pageSize > 200, ErrorCode.PARAMS_ERROR);
        // 普通用户默认只能查看已过审的数据
        pictureQueryRequest.setReviewStatus(PictureReviewStatusEnum.PASS.getValue());
        //  不管使用哪个缓存都需要先构建缓存 key
        String queryCondition = JSONUtil.toJsonStr(pictureQueryRequest);
        String hashkey = DigestUtils.md5DigestAsHex(queryCondition.getBytes());
        String redisKey = "picture_backed:listPictureVOByPage" + hashkey;
        /**
         * 使用 Redis 缓存
         */
//        ValueOperations<String, String> valueOps = stringRedisTemplate.opsForValue();
//        String cacheValue = valueOps.get(redisKey);
//        if (cacheValue != null) {
//            // 命中缓存
//            Page<PictureVO> cachePage = JSONUtil.toBean(cacheValue, Page.class);
//            return ResultUtils.success(cachePage);
//        }
//        Page<Picture> picturePage = pictureService.page(new Page<>(current, pageSize),
//                pictureService.getQueryWrapepr(pictureQueryRequest));
//        // 获取返回封装类
//        Page<PictureVO> pictureVOPage = pictureService.getPictureVOPage(picturePage, request);
        // 将查询到的数据进行转换 POJO类转为JSON
//        String cachedValue = JSONUtil.toJsonStr(pictureVOPage);
//        // 设置5-10分钟随机过期时间，防止缓存雪崩
//        int cacheExpireTime = 300+ RandomUtil.randomInt(0, 300);
        // 将数据加入到缓存中
//        valueOps.set(redisKey, cachedValue, cacheExpireTime, TimeUnit.SECONDS);
        /**
         * 使用本地缓存
         */
//        String cacheValue = LOCAL_CACHE.getIfPresent(redisKey);
//        if (cacheValue != null) {
//            // 命中缓存
//            Page<PictureVO> cachePage = JSONUtil.toBean(cacheValue, Page.class);
//            return ResultUtils.success(cachePage);
//        }
//        // 缓存未命中 查询数据库
//        Page<Picture> picturePage = pictureService.page(new Page<>(current, pageSize),
//                pictureService.getQueryWrapepr(pictureQueryRequest));
//        // 获取返回封装类
//        Page<PictureVO> pictureVOPage = pictureService.getPictureVOPage(picturePage, request);
//
//        // 将数据库中的数据加入到缓存中
//        String cachedValue = JSONUtil.toJsonStr(pictureVOPage);
//        // 不判断缓存是否存在，防止缓存穿透，直接加入到缓存中
//        LOCAL_CACHE.put(redisKey,cachedValue);
        /**
         * 使用多级缓存
         * 优先查询本地缓存，本地缓存中不存在则查询Redis缓存，Redis缓存中不存在则查询数据库
         */
        String cacheValue = LOCAL_CACHE.getIfPresent(redisKey);
        if (cacheValue != null) {
            // 命中缓存
            Page<PictureVO> cachePage = JSONUtil.toBean(cacheValue, Page.class);
            return ResultUtils.success(cachePage);
        }
        // 没有命中本地缓存，查询Redis缓存
        ValueOperations<String, String> valueOps = stringRedisTemplate.opsForValue();
        cacheValue = valueOps.get(redisKey);
        if (cacheValue != null) {
            // 命中缓存，将Redis缓存中的数据加入到本地缓存中
            LOCAL_CACHE.put(redisKey, cacheValue);
            Page<PictureVO> cachePage = JSONUtil.toBean(cacheValue, Page.class);
            return ResultUtils.success(cachePage);
        }
        // 都没有命中缓存，查询数据库，并将数据插入到本地缓存和Redis缓存中
        Page<Picture> picturePage = pictureService.page(new Page<>(current, pageSize),
                pictureService.getQueryWrapepr(pictureQueryRequest));
        // 获取返回封装类
        Page<PictureVO> pictureVOPage = pictureService.getPictureVOPage(picturePage, request);
        // 类型转换
        String cachedValue = JSONUtil.toJsonStr(pictureVOPage);
        // 更新本地缓存，在创建本地缓存时，就已经设置了过期时间为5分钟
        LOCAL_CACHE.put(redisKey, cachedValue);
        // 插入Redis缓存
        // 设置5-10分钟随机过期时间，防止缓存雪崩
        int cacheExpireTime = 300 + RandomUtil.randomInt(0, 300);
        valueOps.set(redisKey, cachedValue, cacheExpireTime, TimeUnit.SECONDS);
        return ResultUtils.success(pictureVOPage);
    }

    /**
     * 编辑图片（用户使用）
     */
    @PostMapping("/edit")
    @ApiOperation("用户编辑图片")
    @SaSpaceCheckPermission(value = SpaceUserPermissionConstant.PICTURE_EDIT)
    public BaseResponse<Boolean> editPicture(@RequestBody PictureEditRequest pictureEditRequest,
                                             HttpServletRequest request) {
        if (pictureEditRequest == null || pictureEditRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        User loginUser = userService.getLoginUser(request);
        pictureService.editPicture(pictureEditRequest, loginUser);
        return ResultUtils.success(true);
    }

    /**
     * 获取预设的标签和分类
     */
    @GetMapping("/tag_category")
    @ApiOperation("获取预设的标签和分类")
    public BaseResponse<PictureTagCategory> getTagAndCategory() {
        PictureTagCategory pictureTagCategory = new PictureTagCategory();
        List<String> tagList = Arrays.asList("热门", "搞笑", "生活", "高清", "艺术", "校园", "背景", "简历", "创意");
        List<String> categoryList = Arrays.asList("模板", "电商", "表情包", "素材", "海报");
        pictureTagCategory.setTagList(tagList);
        pictureTagCategory.setCategoryList(categoryList);
        return ResultUtils.success(pictureTagCategory);
    }

    /**
     * 图片审核（仅管理员）
     */
    @PostMapping("/review")
    @ApiOperation("图片审核")
    @AuthCheck(mustRole = UserContant.ADMIN_ROLE)
    public BaseResponse<Boolean> doPictureReview(@RequestBody PictureReviewRequest pictureReviewRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(pictureReviewRequest == null, ErrorCode.PARAMS_ERROR);
        User loginUser = userService.getLoginUser(request);
        pictureService.doPictureReview(pictureReviewRequest, loginUser);
        return ResultUtils.success(true);
    }


    /**
     * 批量拉取图片（仅管理员）
     */
    @PostMapping("/upload/batch")
    @ApiOperation("图片拉取")
    @AuthCheck(mustRole = UserContant.ADMIN_ROLE)
    public BaseResponse<Integer> uploadPictureByBatch(@RequestBody PictureUploadByBatchRequest pictureUploadByBatchRequest,
                                                      HttpServletRequest request) {
        ThrowUtils.throwIf(pictureUploadByBatchRequest == null, ErrorCode.PARAMS_ERROR);
        User loginUser = userService.getLoginUser(request);
        int uploadCount = pictureService.uploadPictureByBatch(pictureUploadByBatchRequest, loginUser);
        return ResultUtils.success(uploadCount);
    }

    /**
     * 上传图片链接搜图
     */
    @PostMapping("/search/picture")
    @ApiOperation("以图搜图")
    public BaseResponse<List<ImageSearchResult>> searchPicture(@RequestBody SearchPictureByPictureRequest searchPictureByPictureRequest) {
        ThrowUtils.throwIf(searchPictureByPictureRequest == null, ErrorCode.PARAMS_ERROR);
        Long pictureId = searchPictureByPictureRequest.getPictureId();
        ThrowUtils.throwIf(pictureId == null || pictureId <= 0, ErrorCode.PARAMS_ERROR);
        Picture picture = pictureService.getById(pictureId);
        ThrowUtils.throwIf(picture == null, ErrorCode.NOT_FOUND_ERROR);
        List<ImageSearchResult> resultList = ImageSearchApiFacade.searchImage(picture.getUrl());
        return ResultUtils.success(resultList);
    }

    /**
     * 根据颜色搜索自己空间中的图片
     *
     * @param searchPictureByColorRequest
     * @param request
     * @return
     */
    @PostMapping("/search/color")
    @ApiOperation("以色搜图")
    @SaSpaceCheckPermission(value = SpaceUserPermissionConstant.PICTURE_VIEW)
    public BaseResponse<List<PictureVO>> searchPicture(@RequestBody SearchPictureByColorRequest searchPictureByColorRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(searchPictureByColorRequest == null, ErrorCode.PARAMS_ERROR);
        String picColor = searchPictureByColorRequest.getPicColor();
        Long spaceId = searchPictureByColorRequest.getSpaceId();
        User loginUser = userService.getLoginUser(request);
        List<PictureVO> result = pictureService.searchPictureByColor(spaceId, picColor, loginUser);
        return ResultUtils.success(result);
    }

    /**
     * 批量编辑图片
     */
    @PostMapping("/edit/batch")
    @ApiOperation("用户批量编辑图片")
    @SaSpaceCheckPermission(value = SpaceUserPermissionConstant.PICTURE_EDIT)
    public BaseResponse<Boolean> editPictureByBatch(@RequestBody PictureEditByBatchRequest pictureEditByBatchRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(pictureEditByBatchRequest == null, ErrorCode.PARAMS_ERROR);
        User loginUser = userService.getLoginUser(request);
        pictureService.editPictureByBatch(pictureEditByBatchRequest, loginUser);
        return ResultUtils.success(true);
    }

    /**
     * 创建AI 扩图任务
     */
    @PostMapping("/out_painting/create_task")
    @ApiOperation("创建AI 扩图任务")
    public BaseResponse<CreateOutPaintingTaskResponse> createOutPaintingTask(@RequestBody CreatePictureOutPaintingTaskRequest createPictureOutPaintingTaskRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(createPictureOutPaintingTaskRequest == null || createPictureOutPaintingTaskRequest.getPictureId() == null, ErrorCode.PARAMS_ERROR);
        User loginUser = userService.getLoginUser(request);
        CreateOutPaintingTaskResponse response = pictureService.createPictureOutPaintingTask(createPictureOutPaintingTaskRequest, loginUser);
        return ResultUtils.success(response);
    }

    /**
     * 获取AI 扩图任务结果
     */
    @GetMapping("/out_painting/get_task")
    @ApiOperation("获取AI 扩图任务结果")
    @SaSpaceCheckPermission(value = SpaceUserPermissionConstant.PICTURE_EDIT)
    public BaseResponse<GetOutPaintingTaskResponse> getOutPaintingTask(String taskId) {
        ThrowUtils.throwIf(StrUtil.isBlank(taskId), ErrorCode.PARAMS_ERROR);
        GetOutPaintingTaskResponse task = aliYunAiApi.getOutPaintingTask(taskId);
        return ResultUtils.success(task);
    }
}
































